home *** CD-ROM | disk | FTP | other *** search
/ OpenGL Superbible (2nd Edition) / OpenGL SuperBible e2.iso / tools / GLUT-3.7 / PROGS / ADVANCED / PROJTEX.C < prev    next >
Encoding:
C/C++ Source or Header  |  1998-08-12  |  20.6 KB  |  917 lines

  1.  
  2. /* projtex.c - by David Yu and David Blythe, SGI */
  3.  
  4. /**
  5.  ** Demonstrates simple projective texture mapping.
  6.  **
  7.  ** Button1 changes view, Button2 moves texture.
  8.  **
  9.  ** (See: Segal, Korobkin, van Widenfelt, Foran, and Haeberli
  10.  **  "Fast Shadows and Lighting Effects Using Texture Mapping", SIGGRAPH '92)
  11.  **
  12.  ** 1994,1995 -- David G Yu
  13.  **
  14.  ** cc -o projtex projtex.c texture.c -lglut -lGLU -lGL -lX11 -lm
  15.  **/
  16.  
  17. #include <stdio.h>
  18. #include <stdlib.h>
  19. #include <math.h>
  20. #include <GL/glut.h>
  21. #include "texture.h"
  22.  
  23. /* Some <math.h> files do not define M_PI... */
  24. #ifndef M_PI
  25. #define M_PI 3.14159265358979323846
  26. #endif
  27.  
  28. int winWidth, winHeight;
  29.  
  30. GLboolean redrawContinuously = GL_FALSE;
  31.  
  32. float angle, axis[3];
  33. enum MoveModes {
  34.   MoveNone, MoveView, MoveObject, MoveTexture
  35. };
  36. enum MoveModes mode = MoveNone;
  37.  
  38. GLfloat objectXform[4][4];
  39. GLfloat textureXform[4][4];
  40.  
  41. void (*drawObject) (void);
  42. void (*loadTexture) (void);
  43. GLboolean textureEnabled = GL_TRUE;
  44. GLboolean showProjection = GL_TRUE;
  45. GLboolean linearFilter = GL_TRUE;
  46.  
  47. char *texFilename = NULL;
  48.  
  49. GLfloat zoomFactor = 1.0;
  50.  
  51. /*****************************************************************/
  52.  
  53. /* matrix = identity */
  54. void
  55. matrixIdentity(GLfloat matrix[16])
  56. {
  57.   matrix[0] = 1.0;
  58.   matrix[1] = 0.0;
  59.   matrix[2] = 0.0;
  60.   matrix[3] = 0.0;
  61.   matrix[4] = 0.0;
  62.   matrix[5] = 1.0;
  63.   matrix[6] = 0.0;
  64.   matrix[7] = 0.0;
  65.   matrix[8] = 0.0;
  66.   matrix[9] = 0.0;
  67.   matrix[10] = 1.0;
  68.   matrix[11] = 0.0;
  69.   matrix[12] = 0.0;
  70.   matrix[13] = 0.0;
  71.   matrix[14] = 0.0;
  72.   matrix[15] = 1.0;
  73. }
  74.  
  75. /* matrix2 = transpose(matrix1) */
  76. void
  77. matrixTranspose(GLfloat matrix2[16], GLfloat matrix1[16])
  78. {
  79.   matrix2[0] = matrix1[0];
  80.   matrix2[1] = matrix1[4];
  81.   matrix2[2] = matrix1[8];
  82.   matrix2[3] = matrix1[12];
  83.  
  84.   matrix2[4] = matrix1[1];
  85.   matrix2[5] = matrix1[5];
  86.   matrix2[6] = matrix1[9];
  87.   matrix2[7] = matrix1[13];
  88.  
  89.   matrix2[8] = matrix1[2];
  90.   matrix2[9] = matrix1[6];
  91.   matrix2[10] = matrix1[10];
  92.   matrix2[11] = matrix1[14];
  93.  
  94.   matrix2[12] = matrix1[3];
  95.   matrix2[13] = matrix1[7];
  96.   matrix2[14] = matrix1[14];
  97.   matrix2[15] = matrix1[15];
  98. }
  99.  
  100. /*****************************************************************/
  101.  
  102. /* load SGI .rgb image (pad with a border of the specified width and color) */
  103. static void
  104. imgLoad(char *filenameIn, int borderIn, GLfloat borderColorIn[4],
  105.   int *wOut, int *hOut, GLubyte ** imgOut)
  106. {
  107.   int border = borderIn;
  108.   int width, height;
  109.   int w, h;
  110.   GLubyte *image, *img, *p;
  111.   int i, j, components;
  112.  
  113.   image = (GLubyte *) read_texture(filenameIn, &width, &height, &components);
  114.   w = width + 2 * border;
  115.   h = height + 2 * border;
  116.   img = (GLubyte *) calloc(w * h, 4 * sizeof(unsigned char));
  117.  
  118.   p = img;
  119.   for (j = -border; j < height + border; ++j) {
  120.     for (i = -border; i < width + border; ++i) {
  121.       if (0 <= j && j <= height - 1 && 0 <= i && i <= width - 1) {
  122.         p[0] = image[4 * (j * width + i) + 0];
  123.         p[1] = image[4 * (j * width + i) + 1];
  124.         p[2] = image[4 * (j * width + i) + 2];
  125.         p[3] = 0xff;
  126.       } else {
  127.         p[0] = borderColorIn[0] * 0xff;
  128.         p[1] = borderColorIn[1] * 0xff;
  129.         p[2] = borderColorIn[2] * 0xff;
  130.         p[3] = borderColorIn[3] * 0xff;
  131.       }
  132.       p += 4;
  133.     }
  134.   }
  135.   free(image);
  136.   *wOut = w;
  137.   *hOut = h;
  138.   *imgOut = img;
  139. }
  140.  
  141. /*****************************************************************/
  142.  
  143. /* Load the image file specified on the command line as the current texture */
  144. void
  145. loadImageTexture(void)
  146. {
  147.   static int texWidth, texHeight;
  148.   static GLubyte *texData;
  149.   GLfloat borderColor[4] =
  150.   {1.0, 1.0, 1.0, 1.0};
  151.  
  152.   if (!texData && texFilename) {
  153.     imgLoad(texFilename, 2, borderColor, &texWidth, &texHeight, &texData);
  154.   }
  155.   if (linearFilter) {
  156.     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
  157.     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
  158.   } else {
  159.     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
  160.     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
  161.   }
  162.   glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, borderColor);
  163.   gluBuild2DMipmaps(GL_TEXTURE_2D, 4, texWidth, texHeight,
  164.     GL_RGBA, GL_UNSIGNED_BYTE, texData);
  165. }
  166.  
  167. /* Create a simple spotlight pattern and make it the current texture */
  168. void
  169. loadSpotlightTexture(void)
  170. {
  171.   static int texWidth = 64, texHeight = 64;
  172.   static GLubyte *texData;
  173.   GLfloat borderColor[4] =
  174.   {0.1, 0.1, 0.1, 1.0};
  175.  
  176.   if (!texData) {
  177.     GLubyte *p;
  178.     int i, j;
  179.  
  180.     texData = (GLubyte *) malloc(texWidth * texHeight * 4 * sizeof(GLubyte));
  181.  
  182.     p = texData;
  183.     for (j = 0; j < texHeight; ++j) {
  184.       float dy = (texHeight * 0.5 - j + 0.5) / (texHeight * 0.5);
  185.  
  186.       for (i = 0; i < texWidth; ++i) {
  187.         float dx = (texWidth * 0.5 - i + 0.5) / (texWidth * 0.5);
  188.         float r = cos(M_PI / 2.0 * sqrt(dx * dx + dy * dy));
  189.         float c;
  190.  
  191.         r = (r < 0) ? 0 : r * r;
  192.         c = 0xff * (r + borderColor[0]);
  193.         p[0] = (c <= 0xff) ? c : 0xff;
  194.         c = 0xff * (r + borderColor[1]);
  195.         p[1] = (c <= 0xff) ? c : 0xff;
  196.         c = 0xff * (r + borderColor[2]);
  197.         p[2] = (c <= 0xff) ? c : 0xff;
  198.         c = 0xff * (r + borderColor[3]);
  199.         p[3] = (c <= 0xff) ? c : 0xff;
  200.         p += 4;
  201.       }
  202.     }
  203.   }
  204.   if (linearFilter) {
  205.     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
  206.     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
  207.   } else {
  208.     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
  209.     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
  210.   }
  211.   glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, borderColor);
  212.   gluBuild2DMipmaps(GL_TEXTURE_2D, 4, texWidth, texHeight,
  213.     GL_RGBA, GL_UNSIGNED_BYTE, texData);
  214. }
  215.  
  216. /*****************************************************************/
  217.  
  218. void
  219. checkErrors(void)
  220. {
  221.   GLenum error;
  222.   while ((error = glGetError()) != GL_NO_ERROR) {
  223.     fprintf(stderr, "Error: %s\n", (char *) gluErrorString(error));
  224.   }
  225. }
  226.  
  227. void
  228. drawCube(void)
  229. {
  230.   glBegin(GL_QUADS);
  231.  
  232.   glNormal3f(-1.0, 0.0, 0.0);
  233.   glColor3f(0.80, 0.50, 0.50);
  234.   glVertex3f(-0.5, -0.5, -0.5);
  235.   glVertex3f(-0.5, -0.5, 0.5);
  236.   glVertex3f(-0.5, 0.5, 0.5);
  237.   glVertex3f(-0.5, 0.5, -0.5);
  238.  
  239.   glNormal3f(1.0, 0.0, 0.0);
  240.   glColor3f(0.50, 0.80, 0.50);
  241.   glVertex3f(0.5, 0.5, 0.5);
  242.   glVertex3f(0.5, -0.5, 0.5);
  243.   glVertex3f(0.5, -0.5, -0.5);
  244.   glVertex3f(0.5, 0.5, -0.5);
  245.  
  246.   glNormal3f(0.0, -1.0, 0.0);
  247.   glColor3f(0.50, 0.50, 0.80);
  248.   glVertex3f(-0.5, -0.5, -0.5);
  249.   glVertex3f(0.5, -0.5, -0.5);
  250.   glVertex3f(0.5, -0.5, 0.5);
  251.   glVertex3f(-0.5, -0.5, 0.5);
  252.  
  253.   glNormal3f(0.0, 1.0, 0.0);
  254.   glColor3f(0.50, 0.80, 0.80);
  255.   glVertex3f(0.5, 0.5, 0.5);
  256.   glVertex3f(0.5, 0.5, -0.5);
  257.   glVertex3f(-0.5, 0.5, -0.5);
  258.   glVertex3f(-0.5, 0.5, 0.5);
  259.  
  260.   glNormal3f(0.0, 0.0, -1.0);
  261.   glColor3f(0.80, 0.50, 0.80);
  262.   glVertex3f(-0.5, -0.5, -0.5);
  263.   glVertex3f(-0.5, 0.5, -0.5);
  264.   glVertex3f(0.5, 0.5, -0.5);
  265.   glVertex3f(0.5, -0.5, -0.5);
  266.  
  267.   glNormal3f(0.0, 0.0, 1.0);
  268.   glColor3f(1.00, 0.80, 0.50);
  269.   glVertex3f(0.5, 0.5, 0.5);
  270.   glVertex3f(-0.5, 0.5, 0.5);
  271.   glVertex3f(-0.5, -0.5, 0.5);
  272.   glVertex3f(0.5, -0.5, 0.5);
  273.   glEnd();
  274. }
  275.  
  276. void
  277. drawDodecahedron(void)
  278. {
  279. #define A (0.5 * 1.61803)  /* (sqrt(5) + 1) / 2 */
  280. #define B (0.5 * 0.61803)  /* (sqrt(5) - 1) / 2 */
  281. #define C (0.5 * 1.0)
  282.   GLfloat vertexes[20][3] =
  283.   {
  284.     {-A, 0.0, B},
  285.     {-A, 0.0, -B},
  286.     {A, 0.0, -B},
  287.     {A, 0.0, B},
  288.     {B, -A, 0.0},
  289.     {-B, -A, 0.0},
  290.     {-B, A, 0.0},
  291.     {B, A, 0.0},
  292.     {0.0, B, -A},
  293.     {0.0, -B, -A},
  294.     {0.0, -B, A},
  295.     {0.0, B, A},
  296.     {-C, -C, C},
  297.     {-C, -C, -C},
  298.     {C, -C, -C},
  299.     {C, -C, C},
  300.     {-C, C, C},
  301.     {-C, C, -C},
  302.     {C, C, -C},
  303.     {C, C, C},
  304.   };
  305. #undef A
  306. #undef B
  307. #undef C
  308.   GLint polygons[12][5] =
  309.   {
  310.     {0, 12, 10, 11, 16},
  311.     {1, 17, 8, 9, 13},
  312.     {2, 14, 9, 8, 18},
  313.     {3, 19, 11, 10, 15},
  314.     {4, 14, 2, 3, 15},
  315.     {5, 12, 0, 1, 13},
  316.     {6, 17, 1, 0, 16},
  317.     {7, 19, 3, 2, 18},
  318.     {8, 17, 6, 7, 18},
  319.     {9, 14, 4, 5, 13},
  320.     {10, 12, 5, 4, 15},
  321.     {11, 19, 7, 6, 16},
  322.   };
  323.   int i;
  324.  
  325.   glColor3f(0.75, 0.75, 0.75);
  326.   for (i = 0; i < 12; ++i) {
  327.     GLfloat *p0, *p1, *p2, d;
  328.     GLfloat u[3], v[3], n[3];
  329.  
  330.     p0 = &vertexes[polygons[i][0]][0];
  331.     p1 = &vertexes[polygons[i][1]][0];
  332.     p2 = &vertexes[polygons[i][2]][0];
  333.  
  334.     u[0] = p2[0] - p1[0];
  335.     u[1] = p2[1] - p1[1];
  336.     u[2] = p2[2] - p1[2];
  337.  
  338.     v[0] = p0[0] - p1[0];
  339.     v[1] = p0[1] - p1[1];
  340.     v[2] = p0[2] - p1[2];
  341.  
  342.     n[0] = u[1] * v[2] - u[2] * v[1];
  343.     n[1] = u[2] * v[0] - u[0] * v[2];
  344.     n[2] = u[0] * v[1] - u[1] * v[0];
  345.  
  346.     d = 1.0 / sqrt(n[0] * n[0] + n[1] * n[1] + n[2] * n[2]);
  347.     n[0] *= d;
  348.     n[1] *= d;
  349.     n[2] *= d;
  350.  
  351.     glBegin(GL_POLYGON);
  352.     glNormal3fv(n);
  353.     glVertex3fv(p0);
  354.     glVertex3fv(p1);
  355.     glVertex3fv(p2);
  356.     glVertex3fv(vertexes[polygons[i][3]]);
  357.     glVertex3fv(vertexes[polygons[i][4]]);
  358.     glEnd();
  359.   }
  360. }
  361.  
  362. void
  363. drawSphere(void)
  364. {
  365.   int numMajor = 24;
  366.   int numMinor = 32;
  367.   float radius = 0.8;
  368.   double majorStep = (M_PI / numMajor);
  369.   double minorStep = (2.0 * M_PI / numMinor);
  370.   int i, j;
  371.  
  372.   glColor3f(0.50, 0.50, 0.50);
  373.   for (i = 0; i < numMajor; ++i) {
  374.     double a = i * majorStep;
  375.     double b = a + majorStep;
  376.     double r0 = radius * sin(a);
  377.     double r1 = radius * sin(b);
  378.     GLfloat z0 = radius * cos(a);
  379.     GLfloat z1 = radius * cos(b);
  380.  
  381.     glBegin(GL_TRIANGLE_STRIP);
  382.     for (j = 0; j <= numMinor; ++j) {
  383.       double c = j * minorStep;
  384.       GLfloat x = cos(c);
  385.       GLfloat y = sin(c);
  386.  
  387.       glNormal3f((x * r0) / radius, (y * r0) / radius, z0 / radius);
  388.       glTexCoord2f(j / (GLfloat) numMinor, i / (GLfloat) numMajor);
  389.       glVertex3f(x * r0, y * r0, z0);
  390.  
  391.       glNormal3f((x * r1) / radius, (y * r1) / radius, z1 / radius);
  392.       glTexCoord2f(j / (GLfloat) numMinor, (i + 1) / (GLfloat) numMajor);
  393.       glVertex3f(x * r1, y * r1, z1);
  394.     }
  395.     glEnd();
  396.   }
  397. }
  398.  
  399. /*****************************************************************/
  400.  
  401. float xmin = -0.035, xmax = 0.035;
  402. float ymin = -0.035, ymax = 0.035;
  403. float nnear = 0.1;
  404. float ffar = 1.9;
  405. float distance = -1.0;
  406.  
  407. static void
  408. loadTextureProjection(GLfloat m[16])
  409. {
  410.   GLfloat mInverse[4][4];
  411.  
  412.   /* Should use true inverse, but since m consists only of rotations, we can
  413.      just use the transpose. */
  414.   matrixTranspose((GLfloat *) mInverse, m);
  415.  
  416.   glMatrixMode(GL_TEXTURE);
  417.   glLoadIdentity();
  418.   glTranslatef(0.5, 0.5, 0.0);
  419.   glScalef(0.5, 0.5, 1.0);
  420.   glFrustum(xmin, xmax, ymin, ymax, nnear, ffar);
  421.   glTranslatef(0.0, 0.0, distance);
  422.   glMultMatrixf((GLfloat *) mInverse);
  423.   glMatrixMode(GL_MODELVIEW);
  424. }
  425.  
  426. static void
  427. drawTextureProjection(void)
  428. {
  429.   float t = ffar / nnear;
  430.   GLfloat n[4][3];
  431.   GLfloat f[4][3];
  432.  
  433.   n[0][0] = xmin;
  434.   n[0][1] = ymin;
  435.   n[0][2] = -(nnear + distance);
  436.  
  437.   n[1][0] = xmax;
  438.   n[1][1] = ymin;
  439.   n[1][2] = -(nnear + distance);
  440.  
  441.   n[2][0] = xmax;
  442.   n[2][1] = ymax;
  443.   n[2][2] = -(nnear + distance);
  444.  
  445.   n[3][0] = xmin;
  446.   n[3][1] = ymax;
  447.   n[3][2] = -(nnear + distance);
  448.  
  449.   f[0][0] = xmin * t;
  450.   f[0][1] = ymin * t;
  451.   f[0][2] = -(ffar + distance);
  452.  
  453.   f[1][0] = xmax * t;
  454.   f[1][1] = ymin * t;
  455.   f[1][2] = -(ffar + distance);
  456.  
  457.   f[2][0] = xmax * t;
  458.   f[2][1] = ymax * t;
  459.   f[2][2] = -(ffar + distance);
  460.  
  461.   f[3][0] = xmin * t;
  462.   f[3][1] = ymax * t;
  463.   f[3][2] = -(ffar + distance);
  464.  
  465.   glColor3f(1.0, 1.0, 0.0);
  466.   glBegin(GL_LINE_LOOP);
  467.   glVertex3fv(n[0]);
  468.   glVertex3fv(n[1]);
  469.   glVertex3fv(n[2]);
  470.   glVertex3fv(n[3]);
  471.   glVertex3fv(f[3]);
  472.   glVertex3fv(f[2]);
  473.   glVertex3fv(f[1]);
  474.   glVertex3fv(f[0]);
  475.   glVertex3fv(n[0]);
  476.   glVertex3fv(n[1]);
  477.   glVertex3fv(f[1]);
  478.   glVertex3fv(f[0]);
  479.   glVertex3fv(f[3]);
  480.   glVertex3fv(f[2]);
  481.   glVertex3fv(n[2]);
  482.   glVertex3fv(n[3]);
  483.   glEnd();
  484. }
  485.  
  486. /*****************************************************************/
  487.  
  488. void
  489. initialize(void)
  490. {
  491.   GLfloat light0Pos[4] =
  492.   {0.3, 0.3, 0.0, 1.0};
  493.   GLfloat matAmb[4] =
  494.   {0.01, 0.01, 0.01, 1.00};
  495.   GLfloat matDiff[4] =
  496.   {0.65, 0.65, 0.65, 1.00};
  497.   GLfloat matSpec[4] =
  498.   {0.30, 0.30, 0.30, 1.00};
  499.   GLfloat matShine = 10.0;
  500.   GLfloat eyePlaneS[] =
  501.   {1.0, 0.0, 0.0, 0.0};
  502.   GLfloat eyePlaneT[] =
  503.   {0.0, 1.0, 0.0, 0.0};
  504.   GLfloat eyePlaneR[] =
  505.   {0.0, 0.0, 1.0, 0.0};
  506.   GLfloat eyePlaneQ[] =
  507.   {0.0, 0.0, 0.0, 1.0};
  508.  
  509.   /* Setup Misc.  */
  510.   glClearColor(0.41, 0.41, 0.31, 0.0);
  511.  
  512.   glEnable(GL_DEPTH_TEST);
  513.  
  514.   glLineWidth(2.0);
  515.  
  516.   glCullFace(GL_FRONT);
  517.   glEnable(GL_CULL_FACE);
  518.  
  519.   glMatrixMode(GL_PROJECTION);
  520.   glFrustum(-0.5, 0.5, -0.5, 0.5, 1, 3);
  521.   glMatrixMode(GL_MODELVIEW);
  522.   glTranslatef(0, 0, -2);
  523.  
  524.   matrixIdentity((GLfloat *) objectXform);
  525.   matrixIdentity((GLfloat *) textureXform);
  526.  
  527.   glMatrixMode(GL_PROJECTION);
  528.   glPushMatrix();
  529.   glLoadIdentity();
  530.   glOrtho(0, 1, 0, 1, -1, 1);
  531.   glMatrixMode(GL_MODELVIEW);
  532.   glPushMatrix();
  533.   glLoadIdentity();
  534.  
  535.   glRasterPos2i(0, 0);
  536.  
  537.   glPopMatrix();
  538.   glMatrixMode(GL_PROJECTION);
  539.   glPopMatrix();
  540.   glMatrixMode(GL_MODELVIEW);
  541.  
  542.   /* Setup Lighting */
  543.   glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, matAmb);
  544.   glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, matDiff);
  545.   glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, matSpec);
  546.   glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, matShine);
  547.  
  548.   glEnable(GL_COLOR_MATERIAL);
  549.  
  550.   glLightfv(GL_LIGHT0, GL_POSITION, light0Pos);
  551.   glEnable(GL_LIGHT0);
  552.  
  553.   glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_TRUE);
  554.   glEnable(GL_LIGHTING);
  555.  
  556.   /* Setup Texture */
  557.   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
  558.   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
  559.   glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
  560.   (*loadTexture) ();
  561.  
  562.   glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
  563.   glTexGenfv(GL_S, GL_EYE_PLANE, eyePlaneS);
  564.  
  565.   glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
  566.   glTexGenfv(GL_T, GL_EYE_PLANE, eyePlaneT);
  567.  
  568.   glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
  569.   glTexGenfv(GL_R, GL_EYE_PLANE, eyePlaneR);
  570.  
  571.   glTexGeni(GL_Q, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
  572.   glTexGenfv(GL_Q, GL_EYE_PLANE, eyePlaneQ);
  573. }
  574.  
  575. void
  576. display(void)
  577. {
  578.   glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
  579.  
  580.   if (textureEnabled) {
  581.     if (mode == MoveTexture || mode == MoveView) {
  582.       /* Have OpenGL compute the new transformation (simple but slow). */
  583.       glPushMatrix();
  584.       glLoadIdentity();
  585.       glRotatef(angle, axis[0], axis[1], axis[2]);
  586.       glMultMatrixf((GLfloat *) textureXform);
  587.       glGetFloatv(GL_MODELVIEW_MATRIX, (GLfloat *) textureXform);
  588.       glPopMatrix();
  589.     }
  590.     loadTextureProjection((GLfloat *) textureXform);
  591.  
  592.     if (showProjection) {
  593.       glPushMatrix();
  594.       glMultMatrixf((GLfloat *) textureXform);
  595.       glDisable(GL_LIGHTING);
  596.       drawTextureProjection();
  597.       glEnable(GL_LIGHTING);
  598.       glPopMatrix();
  599.     }
  600.     glEnable(GL_TEXTURE_2D);
  601.     glEnable(GL_TEXTURE_GEN_S);
  602.     glEnable(GL_TEXTURE_GEN_T);
  603.     glEnable(GL_TEXTURE_GEN_R);
  604.     glEnable(GL_TEXTURE_GEN_Q);
  605.   }
  606.   if (mode == MoveObject || mode == MoveView) {
  607.     /* Have OpenGL compute the new transformation (simple but slow). */
  608.     glPushMatrix();
  609.     glLoadIdentity();
  610.     glRotatef(angle, axis[0], axis[1], axis[2]);
  611.     glMultMatrixf((GLfloat *) objectXform);
  612.     glGetFloatv(GL_MODELVIEW_MATRIX, (GLfloat *) objectXform);
  613.     glPopMatrix();
  614.   }
  615.   glPushMatrix();
  616.   glMultMatrixf((GLfloat *) objectXform);
  617.   (*drawObject) ();
  618.   glPopMatrix();
  619.  
  620.   glDisable(GL_TEXTURE_2D);
  621.   glDisable(GL_TEXTURE_GEN_S);
  622.   glDisable(GL_TEXTURE_GEN_T);
  623.   glDisable(GL_TEXTURE_GEN_R);
  624.   glDisable(GL_TEXTURE_GEN_Q);
  625.  
  626.   if (zoomFactor > 1.0) {
  627.     glDisable(GL_DEPTH_TEST);
  628.     glCopyPixels(0, 0, winWidth / zoomFactor, winHeight / zoomFactor, GL_COLOR);
  629.     glEnable(GL_DEPTH_TEST);
  630.   }
  631.   glFlush();
  632.   glutSwapBuffers();
  633.   checkErrors();
  634. }
  635.  
  636. /*****************************************************************/
  637.  
  638. /* simple trackball-like motion control */
  639. float lastPos[3];
  640. int lastTime;
  641.  
  642. void
  643. ptov(int x, int y, int width, int height, float v[3])
  644. {
  645.   float d, a;
  646.  
  647.   /* project x,y onto a hemi-sphere centered within width, height */
  648.   v[0] = (2.0 * x - width) / width;
  649.   v[1] = (height - 2.0 * y) / height;
  650.   d = sqrt(v[0] * v[0] + v[1] * v[1]);
  651.   v[2] = cos((M_PI / 2.0) * ((d < 1.0) ? d : 1.0));
  652.   a = 1.0 / sqrt(v[0] * v[0] + v[1] * v[1] + v[2] * v[2]);
  653.   v[0] *= a;
  654.   v[1] *= a;
  655.   v[2] *= a;
  656. }
  657.  
  658. void
  659. startMotion(int x, int y, int but, int time)
  660. {
  661.   if (but == GLUT_LEFT_BUTTON) {
  662.     mode = MoveView;
  663.   } else if (but == GLUT_MIDDLE_BUTTON) {
  664.     mode = MoveTexture;
  665.   } else {
  666.     return;
  667.   }
  668.  
  669.   lastTime = time;
  670.   ptov(x, y, winWidth, winHeight, lastPos);
  671. }
  672.  
  673. void
  674. animate(void)
  675. {
  676.   glutPostRedisplay();
  677. }
  678.  
  679. void
  680. vis(int visible)
  681. {
  682.   if (visible == GLUT_VISIBLE) {
  683.     if (redrawContinuously)
  684.       glutIdleFunc(animate);
  685.   } else {
  686.     if (redrawContinuously)
  687.       glutIdleFunc(NULL);
  688.   }
  689. }
  690.  
  691. void
  692. stopMotion(int but, int time)
  693. {
  694.   if ((but == GLUT_LEFT_BUTTON && mode == MoveView) ||
  695.     (but == GLUT_MIDDLE_BUTTON && mode == MoveTexture)) {
  696.   } else {
  697.     return;
  698.   }
  699.  
  700.   if (time == lastTime) {
  701.     redrawContinuously = GL_TRUE;
  702.     glutIdleFunc(animate);
  703.   } else {
  704.     angle = 0.0;
  705.     redrawContinuously = GL_FALSE;
  706.     glutIdleFunc(0);
  707.   }
  708.   if (!redrawContinuously) {
  709.     mode = MoveNone;
  710.   }
  711. }
  712.  
  713. void
  714. trackMotion(int x, int y)
  715. {
  716.   float curPos[3], dx, dy, dz;
  717.  
  718.   ptov(x, y, winWidth, winHeight, curPos);
  719.  
  720.   dx = curPos[0] - lastPos[0];
  721.   dy = curPos[1] - lastPos[1];
  722.   dz = curPos[2] - lastPos[2];
  723.   angle = 90.0 * sqrt(dx * dx + dy * dy + dz * dz);
  724.  
  725.   axis[0] = lastPos[1] * curPos[2] - lastPos[2] * curPos[1];
  726.   axis[1] = lastPos[2] * curPos[0] - lastPos[0] * curPos[2];
  727.   axis[2] = lastPos[0] * curPos[1] - lastPos[1] * curPos[0];
  728.  
  729.   lastTime = glutGet(GLUT_ELAPSED_TIME);
  730.   lastPos[0] = curPos[0];
  731.   lastPos[1] = curPos[1];
  732.   lastPos[2] = curPos[2];
  733.   glutPostRedisplay();
  734. }
  735.  
  736. /*****************************************************************/
  737.  
  738. void
  739. object(void)
  740. {
  741.   static int object;
  742.  
  743.   object++;
  744.   object %= 3;
  745.   switch (object) {
  746.   case 0:
  747.     drawObject = drawCube;
  748.     break;
  749.   case 1:
  750.     drawObject = drawDodecahedron;
  751.     break;
  752.   case 2:
  753.     drawObject = drawSphere;
  754.     break;
  755.   default:
  756.     break;
  757.   }
  758. }
  759.  
  760. static void
  761. nop(void)
  762. {
  763. }
  764.  
  765. void
  766. texture(void)
  767. {
  768.   static int texture = 0;
  769.  
  770.   texture++;
  771.   texture %= 3;
  772.   if (texture == 1 && texFilename == NULL) {
  773.     /* Skip file texture if not loaded. */
  774.     texture++;
  775.   }
  776.   switch (texture) {
  777.   case 0:
  778.     loadTexture = nop;
  779.     textureEnabled = GL_FALSE;
  780.     break;
  781.   case 1:
  782.     loadTexture = loadImageTexture;
  783.     (*loadTexture) ();
  784.     textureEnabled = GL_TRUE;
  785.     break;
  786.   case 2:
  787.     loadTexture = loadSpotlightTexture;
  788.     (*loadTexture) ();
  789.     textureEnabled = GL_TRUE;
  790.     break;
  791.   default:
  792.     break;
  793.   }
  794. }
  795.  
  796. void
  797. help(void)
  798. {
  799.   printf("'h'   - help\n");
  800.   printf("'l'   - toggle linear/nearest filter\n");
  801.   printf("'s'   - toggle projection frustum\n");
  802.   printf("'t'   - toggle projected texture\n");
  803.   printf("'o'   - toggle object\n");
  804.   printf("'z'   - increase zoom factor\n");
  805.   printf("'Z'   - decrease zoom factor\n");
  806.   printf("left mouse     - move view\n");
  807.   printf("middle mouse   - move projection\n");
  808. }
  809.  
  810. /* ARGSUSED1 */
  811. void
  812. key(unsigned char key, int x, int y)
  813. {
  814.   switch (key) {
  815.   case '\033':
  816.     exit(0);
  817.     break;
  818.   case 'l':
  819.     linearFilter = !linearFilter;
  820.     (*loadTexture) ();
  821.     break;
  822.   case 's':
  823.     showProjection = !showProjection;
  824.     break;
  825.   case 't':
  826.     texture();
  827.     break;
  828.   case 'o':
  829.     object();
  830.     break;
  831.   case 'z':
  832.     zoomFactor += 1.0;
  833.     glPixelZoom(zoomFactor, zoomFactor);
  834.     glViewport(0, 0, winWidth / zoomFactor, winHeight / zoomFactor);
  835.     break;
  836.   case 'Z':
  837.     zoomFactor -= 1.0;
  838.     if (zoomFactor < 1.0)
  839.       zoomFactor = 1.0;
  840.     glPixelZoom(zoomFactor, zoomFactor);
  841.     glViewport(0, 0, winWidth / zoomFactor, winHeight / zoomFactor);
  842.     break;
  843.   case 'h':
  844.     help();
  845.     break;
  846.   }
  847.   glutPostRedisplay();
  848. }
  849.  
  850. void
  851. mouse(int button, int state, int x, int y)
  852. {
  853.   if (state == GLUT_DOWN)
  854.     startMotion(x, y, button, glutGet(GLUT_ELAPSED_TIME));
  855.   else if (state == GLUT_UP)
  856.     stopMotion(button, glutGet(GLUT_ELAPSED_TIME));
  857.   glutPostRedisplay();
  858. }
  859.  
  860. void
  861. reshape(int w, int h)
  862. {
  863.   winWidth = w;
  864.   winHeight = h;
  865.   glViewport(0, 0, w / zoomFactor, h / zoomFactor);
  866. }
  867.  
  868. void
  869. usage(char *name)
  870. {
  871.   fprintf(stderr, "usage: %s <image-filename>\n", name);
  872.   fprintf(stderr, "\n");
  873. }
  874.  
  875. void
  876. menu(int selection)
  877. {
  878.   if (selection == 666) {
  879.     exit(0);
  880.   }
  881.   key((unsigned char) selection, 0, 0);
  882. }
  883.  
  884. int
  885. main(int argc, char **argv)
  886. {
  887.   glutInit(&argc, argv);
  888.   glutInitDisplayMode(GLUT_RGBA | GLUT_DEPTH | GLUT_DOUBLE);
  889.   (void) glutCreateWindow("projtex");
  890.   if (argc > 2) {
  891.     usage(argv[0]);
  892.     exit(1);
  893.   }
  894.   if (argc > 1) {
  895.     texFilename = argv[1];
  896.   }
  897.   loadTexture = loadImageTexture;
  898.   drawObject = drawCube;
  899.   initialize();
  900.   glutDisplayFunc(display);
  901.   glutKeyboardFunc(key);
  902.   glutReshapeFunc(reshape);
  903.   glutMouseFunc(mouse);
  904.   glutMotionFunc(trackMotion);
  905.   glutVisibilityFunc(vis);
  906.   glutCreateMenu(menu);
  907.   glutAddMenuEntry("Toggle showing projection", 's');
  908.   glutAddMenuEntry("Switch texture", 't');
  909.   glutAddMenuEntry("Switch object", 'o');
  910.   glutAddMenuEntry("Toggle filtering", 'l');
  911.   glutAddMenuEntry("Quit", 666);
  912.   glutAttachMenu(GLUT_RIGHT_BUTTON);
  913.   texture();
  914.   glutMainLoop();
  915.   return 0;             /* ANSI C requires main to return int. */
  916. }
  917.